﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OcmKeep
{
    class DataHelper
    {
        private const byte start1 = 0xEF;   //包头
        private const byte start2 = 0x01;   //包头

        public class CMD {
            public static byte[] CMD_ASK = {0xFE,0xEF};//询问发送0xFE 0xEF
            public static byte[] CMD_ERROR = {0x0E,0xE0};//出现错误时发送0x0E 0xE0
            public static byte[] CMD_OPEN = {0x0B,0xB0};//开门
            public static byte[] CMD_FINGER = {0x0C,0xC0};//指纹
            public static byte[] CMD_BUSY ={0x0A,0xA0};//通道忙碌0x0A 0xA0
            public static byte[] CMD_CARD = { 0x0D, 0xD0};//请求卡号
            public static byte[] CMD_FACE = { 0x0F, 0xF0 };//人脸比对中
            public static byte[] CMD_ALLOW = { 0x4A, 0xA4 };//允许临时出场
            public static byte[] CMD_DENY = { 0x3A, 0xA3 };//禁止临时出场
            public static byte[] CMD_ADDR = { 0x2A, 0xA2 };//修改闸机地址
            public static byte[] CMD_PSW = { 0x1A, 0xA1 };//装载闸机密码
        }

        public class ACK
        {
            public static byte[] ACK_CARD = {0x01,0x10};        //请求卡号
            public static byte[] ACK_FINGER = { 0x02, 0x20 };   //请求指纹

            public static byte[] ACK_WATING = {0x03,0x30};     //等待比对指纹
            public static byte[] ACK_SUCCESS = {0x03,0x31};    //比对成功
            public static byte[] ACK_FAIL = { 0x03, 0x32 };       //比对失败
            public static byte[] ACK_EMPTY = { 0x00,0x00}; //空返回
        }

       
        private const int HEADLEN = 9;
        private const int SUMLEN = 2;

        List<Package> PackageList;

        protected class Package {
            private int retrynum=3;
            public byte[] Data { get; set; }
            public int Addr{set;get;}
            public int Valid { set; get; }
            public void DecRetry (){ 
                if(retrynum>0)retrynum--;
            }
            public void ResetRetry() {
                retrynum=3;
            }
            public bool IsRetriable() { 
                return retrynum>0?true:false;
            }
        }

        public DataHelper() {
            PackageList = new List<Package>();
        }

        /// <summary>
        /// 发送 拼接包
        /// </summary>
        /// <param name="addr"></param>
        /// <param name="data"></param>
        /// <param name="CMD"></param>
        /// <param name="Len"></param>
        /// <returns></returns>
        public byte[] GetPackage(int addr, string data,byte[] CMD,ref int Len)
        {
            int datalen = data.Length / 2;
            byte[] temp = new byte[datalen + HEADLEN+SUMLEN];
            Len = datalen + HEADLEN + SUMLEN;
            byte[] packlen;
            byte devAddr = Convert.ToByte(addr);
            packlen = BitConverter.GetBytes((short)datalen+2);
            temp[0] = devAddr;      //设备地址
            temp[1] = start1;       //包头
            temp[2] = start2;       //包头
            temp[3] = 0xff;         //设备号0xFFXX 0xff未固定值
            temp[4] = devAddr;      //设备号 XX为设备号
            temp[5] = CMD[0];   //包命令
            temp[6] = CMD[1];   //包命令
            temp[7] = packlen[1];   //包长度
            temp[8] = packlen[0];  //包长度
            for (int i = 0, j = 9, len = data.Length; i < len; i+=2,j++)
            {
                temp[j] = HexToDec(data.Substring(i, 2));
            }
            Int32 isum = getSUM(temp, datalen, CMD);
            byte[] sum = BitConverter.GetBytes(isum);
            temp[temp.Length - 2] = sum[1];
            temp[temp.Length - 1] = sum[0];
            return temp;
        }

        private byte HexToDec(string str) {
            string tmp = "";
            str = str.ToLower();
            foreach (char s in str) {
                switch (s) {
                    case '0': tmp += "0000"; break;
                    case '1': tmp += "0001"; break;
                    case '2': tmp += "0010"; break;
                    case '3': tmp += "0011"; break;
                    case '4': tmp += "0100"; break;
                    case '5': tmp += "0101"; break;
                    case '6': tmp += "0110"; break;
                    case '7': tmp += "0111"; break;
                    case '8': tmp += "1000"; break;
                    case '9': tmp += "1001"; break;
                    case 'a': tmp += "1010"; break;
                    case 'b': tmp += "1011"; break;
                    case 'c': tmp += "1100"; break;
                    case 'd': tmp += "1101"; break;
                    case 'e': tmp += "1110"; break;
                    case 'f': tmp += "1111"; break;
                }
            }
            int a = Convert.ToInt32(tmp, 2);
            return Convert.ToByte(a);
        }

        private int HexToDecInt(string str)
        {
            string tmp = "";
            str = str.ToLower();
            foreach (char s in str)
            {
                switch (s)
                {
                    case '0': tmp += "0000"; break;
                    case '1': tmp += "0001"; break;
                    case '2': tmp += "0010"; break;
                    case '3': tmp += "0011"; break;
                    case '4': tmp += "0100"; break;
                    case '5': tmp += "0101"; break;
                    case '6': tmp += "0110"; break;
                    case '7': tmp += "0111"; break;
                    case '8': tmp += "1000"; break;
                    case '9': tmp += "1001"; break;
                    case 'a': tmp += "1010"; break;
                    case 'b': tmp += "1011"; break;
                    case 'c': tmp += "1100"; break;
                    case 'd': tmp += "1101"; break;
                    case 'e': tmp += "1110"; break;
                    case 'f': tmp += "1111"; break;
                }
            }
            return Convert.ToInt32(tmp, 2);
        }

        /// <summary>
        /// 解析包内容
        /// </summary>
        /// <returns></returns>
        public string GetData(byte[] data) {
            int len = GetPackLen(data);
            if (len <= 0) return "";
            string tmp = BitConverter.ToString(data, HEADLEN, len);
            tmp =  tmp.Length>0?tmp.Replace("-", ""):tmp;
            return tmp.Substring(0,8);
        }

        private int GetPackLen(byte[] data)
        {
            string tmp = BitConverter.ToString(data, 7, 2);
            if(tmp.Length>0)tmp = tmp.Replace("-", "");
            return HexToDecInt(tmp.Substring(0, 2)) + HexToDecInt(tmp.Substring(2, 2)) - 2;
        }

        public byte[] GetACK(byte[] data)
        {
            byte[] tmp = new byte[2];
            tmp[0]=data[5];
            tmp[1] = data[6];
            return tmp;
        }

        public int GetAddr(byte[] data)
        {
            try
            {
                return int.Parse(BitConverter.ToString(data, 0, 1),System.Globalization.NumberStyles.AllowHexSpecifier);
            }
            catch (Exception e)
            {
                Form1.DebugLog(e.Message+e.StackTrace);
                Console.WriteLine(e.StackTrace);
                return -1;
            }
            
        }

        public int GetValidSum(byte[] data,int len)
        {
            try
            {
                byte[] tmp = new byte[2];
                if (HEADLEN + len >= data.Length) return -1;
                tmp[0] = data[HEADLEN + len];
                tmp[1] = data[HEADLEN + len + 1];
                string str = BitConverter.ToString(tmp);
                str = str.Length > 0 ? str.Replace("-", "") : "";
                return HexToDecInt(str);
            }
            catch (Exception e)
            {
                Form1.DebugLog(e.Message+e.StackTrace);
                Console.WriteLine(e.StackTrace);
                return -1;
            }
        }

        public bool ValidSum(byte[] data) {
            try
            {
                Int32 len = GetPackLen(data);
                if (len < 0) return false;
                Int32 validSum = GetValidSum(data, len);
                Int32 mathSum = getAckSum(data, len, GetACK(data));
                return validSum == mathSum ? true : false;
            }
            catch (Exception e)
            {
                Form1.DebugLog(e.Message+e.StackTrace);
                Console.WriteLine(e.StackTrace);
                return false;
            }
        }

        public bool EqAck(byte[] Src,byte[] Ack) {
            try
            {
                if (Src[0] == Ack[0] && Src[1] == Ack[1]) return true;
                else return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// 校验和
        /// </summary>
        /// <param name="data">包内容</param>
        /// <param name="length">包长度</param>
        /// <param name="flag"></param>
        /// <returns></returns>
        public int getSUM(byte[] data, int length, byte[] CMD)
        {
            try
            {
                byte[] tmp = new byte[length];
                for (int i = 0; i < length; ++i)
                {
                    tmp[i] = data[9 + i];
                }
                byte[] len = BitConverter.GetBytes(length);
                return Fill(tmp) + Fill(CMD) + Fill(len) + 2;
            }
            catch (Exception e)
            {
                Form1.DebugLog(e.Message+e.StackTrace);
                return 0;
            }
        }


        private UInt16 Fill(byte[] memorySpage)
        {
            int num = 0;
            for (int i = 0; i < memorySpage.Length; i++)
            {
                num = (num + memorySpage[i]) ;
            }
            //实际上num 这里已经是结果了，如果只是取int 可以直接返回了  
            memorySpage = BitConverter.GetBytes(num);
            //返回累加校验和  
            return BitConverter.ToUInt16(new byte[] { memorySpage[0], memorySpage[1] }, 0);
        }  
        private int getAckSum(byte[] data, int length, byte[] Ack)
        {
            try
            {
                if (length < 0||length>=40) return -2;
                byte[] tmp = new byte[length];
                for(int i=0;i<length;++i){
                    tmp[i] = data[9 + i];
                }
                byte[] len = BitConverter.GetBytes(length);
                return Fill(tmp) + Fill(Ack) + Fill(len) + 2;
            }
            catch (Exception e)
            {
                Form1.DebugLog(e.Message+e.StackTrace);
                return 0;
            }
        }
    }
}
